#include "cpu/cpu.h"
#include "core/syscall.h"
#include "comm/cpu_instr.h"
#include "ipc/mutex.h"
#include "os_cfg.h"

static segment_desc_t gdt_table[GDT_TABLE_SIZE];
static mutex_t mutex;


//设置gdt表的属性
void segment_desc_set(int selector,uint32_t base,uint32_t limit,uint16_t attr){
    mutex_lock(&mutex);

    //把base limit attribute写入到gdt表里，写成他那样的格式
    //base 基地址  limit 段的大小
    // select 是从gdt_table地址开始算，偏移了多少字节
    // 一个segment_desc_t是64位，8个字节，第二项就是 gdt_table + (8)/8 第三项 gdt_table + (24)/8
    segment_desc_t * dest=gdt_table + (selector/sizeof(segment_desc_t));
    //当limit > 0xfffff时，G标志位被设置为1
    if(limit > 0xfffff){
        attr=(attr | SEG_G);
        limit=(limit>>12);
    }
    dest->attr=(attr | ((limit&0xf0000)>>8));
    dest->base15_0=(base & 0xffff);
    dest->base23_16=((base>>16)&0xff);
    dest->base31_24=((base>>24)&0xff);
    dest->limit15_0=(limit & 0xffff);

    mutex_unlock(&mutex);
}

void exception_handler_systemcall(void);

//初始化gdt
void init_gdt(){
    //每一项都置为0
    for(int i=0;i<GDT_TABLE_SIZE;i++){
        segment_desc_set((i*(sizeof(segment_desc_t))),0,0,0);
    }

    //初始化cs
    segment_desc_set(KERNEL_SELECTOR_CS,0,0xffffffff,
        SEG_P_PRESENT | SEG_DPL0 | SEG_S_NORMAL | SEG_TYPE_CODE |
        SEG_TYPE_RW | SEG_D
    );
    //初始化ds
    segment_desc_set(KERNEL_SELECTOR_DS,0,0xffffffff,
        SEG_P_PRESENT | SEG_DPL0 | SEG_S_NORMAL | SEG_TYPE_DATA |
        SEG_TYPE_RW | SEG_D
    );
    // 调用门
    gate_desc_set((gate_desc_t *)(gdt_table + (SELECTOR_SYSCALL >> 3)),
            KERNEL_SELECTOR_CS,
            (uint32_t)exception_handler_systemcall,
            GATE_P_PRESENT | GATE_DPL3 | GATE_TYPE_SYSCALL | SYSCALL_PARAM_COUNT);

    //重新加载全局描述表
    lgdt((uint32_t)gdt_table, sizeof(gdt_table));
}

//设置中断描述符的一项
void gate_desc_set(gate_desc_t *desc,uint16_t selector,uint32_t offset,uint16_t attr){
    desc->attr=attr;
    desc->offset15_0=(offset & 0xffff);
    desc->offset31_16=((offset>>16)&0xffff);
    desc->selector=selector;
};


//cpu初始化
void cpu_init(){
    mutex_init(&mutex);
    init_gdt();
}

int gdt_alloc_desc (void) {
    mutex_lock(&mutex);
    //分配一个gdt表项
    for(int i=1;i<GDT_TABLE_SIZE;i++){
        if(gdt_table[i].attr==0){
            mutex_unlock(&mutex);
            return i* sizeof(segment_desc_t);
        }
    }
    mutex_unlock(&mutex);
    return -1;
}


// 清空gdt表项
void gdt_free_desc(int gdt_index){
    mutex_lock(&mutex);
    gdt_table[gdt_index / (sizeof(segment_desc_t))].attr=0;
    mutex_unlock(&mutex);
};

/**
 * 切换至TSS，即跳转实现任务切换
 */
void switch_to_tss (uint32_t tss_selector) {
    far_jump(tss_selector, 0);
}